/*
 * @(#)PascalTriangle.java	1.0 Apr 26, 2008
 *
 *	The MIT License
 *
 *	Copyright (c) 2008 Malachi de AElfweald <malachid@gmail.com>
 *
 *	Permission is hereby granted, free of charge, to any person obtaining a copy
 *	of this software and associated documentation files (the "Software"), to deal
 *	in the Software without restriction, including without limitation the rights
 *	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the Software is
 *	furnished to do so, subject to the following conditions:
 *
 *	The above copyright notice and this permission notice shall be included in
 *	all copies or substantial portions of the Software.
 *
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *	THE SOFTWARE.
 */
package org.eoti.math;

import java.math.BigInteger;
import java.util.*;

public class PascalTriangle
{
	// test
	public static void main(String[] args)
			throws Exception
	{
		int numLines = Integer.parseInt(args[0]);
		PascalTriangle p = new PascalTriangle(numLines);
		try{
			p.display(Integer.parseInt(args[1]));
		} catch(Exception e){
			p.display();
		}
	}

	protected ArrayList<ArrayList<BigInteger>> rows;
	protected int largest = 1;

	public PascalTriangle(int numLines)
	{
		rows = new ArrayList<ArrayList<BigInteger>>();

		ArrayList<BigInteger> firstRow = new ArrayList<BigInteger>();
		firstRow.add(BigInteger.ONE);
		rows.add(firstRow);

		for(int row=1; row<numLines; row++)
		{
			ArrayList<BigInteger> line = new ArrayList<BigInteger>();
			for(int col=0; col<=rowSize(row-1); col++)
			{
				final BigInteger value = getTopLeft(row,col).add(getTopRight(row,col));
				line.add( value );
				largest = Math.max(largest, (value.toString()).length());
			}
			rows.add(line);
		}
	}

	public ArrayList<ArrayList<BigInteger>> getRows(){return rows;}

	public void display(int mask)
	{
		BigInteger maskVal = BigInteger.valueOf(mask);
		// should show it centered
		for(int row=0; row<rows.size(); row++)
		{
			ArrayList<BigInteger> line = rows.get(row);
			for(int col=0; col<line.size(); col++)
			{
				BigInteger val = line.get(col);
				if(val.mod(maskVal).equals(BigInteger.ZERO))
					System.out.print("*");
				else
					System.out.print(" ");
				// I think this logic is only valid for mask=2... 3 should use 0,1,2
//				if(MathUtil.isEven(val))
//					System.out.print("0");
//				else
//					System.out.print("1");
			}
			System.out.println();
		}
	}

	public void display()
	{
		largest = largest+1;
		String even = "-%" + largest + "." + largest + "s";
		String odd = String.format("%" + largest/2 + "." + largest/2 + "s", " ") + even;

		for(int row=0; row<rows.size(); row++)
		{
			for(int col=0; col<(rows.size()-row); col++)
				System.out.format( (col%2==0?even:odd), " ");

			ArrayList<BigInteger> line = rows.get(row);
			for(int col=0; col<line.size(); col++)
				System.out.format( (col%2==0?even:odd), line.get(col));

			System.out.println();
		}
	}

	protected int rowSize(int row)
	{
		if(row < 0)
			return 0;

		if(row >= rows.size())
			return 0;

		return rows.get(row).size();
	}

	protected BigInteger getValue(int row, int col)
	{
		if(row < 0)
			return BigInteger.ZERO;

		if(col < 0)
			return BigInteger.ZERO;

		if(row >= rows.size())
			return BigInteger.ZERO;

		if(col >= rows.get(row).size())
			return BigInteger.ZERO;

		return rows.get(row).get(col);
	}

	protected BigInteger getTopLeft(int currentRow, int currentCol)
	{
		// positions:
		//		 0x0
		//    0x1   1x1
		// 0x2   1x2   2x2
		return getValue(currentRow-1, currentCol-1);
	}

	protected BigInteger getTopRight(int currentRow, int currentCol)
	{
		// positions:
		//		 0x0
		//    0x1   1x1
		// 0x2   1x2   2x2
		return getValue(currentRow-1, currentCol);
	}
}
